package com.technologys.realm;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;

import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.RandomNumberGenerator;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.technologys.dao.UserDao;
import com.technologys.pojo.UserPojo;

public class DefaultJdbcSaltRealm extends AuthorizingRealm {

	private static final Logger log = LoggerFactory.getLogger(DefaultJdbcSaltRealm.class);
	
	private UserDao userDao;
	
	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}
	
	protected boolean permissionsLookupEnabled = false;
	
	public void setPermissionsLookupEnabled(boolean permissionsLookupEnabled) {
		this.permissionsLookupEnabled = permissionsLookupEnabled;
	}
	
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		if (CollectionUtils.isEmpty(principals)) {
            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
        }
		
		String userid = "";
		Collection<?> conn = principals.fromRealm(getName());
		if (CollectionUtils.isEmpty(conn)) {
			userid = (String) principals.getPrimaryPrincipal();
		} else {
			userid = (String) conn.iterator().next();
		}
		log.info("{}", userid);
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		List<String> roles = this.userDao.queryRolesByUserid(userid);
		if (roles != null && roles.size() > 0) {
			info.setRoles(new HashSet<String>(roles));
			if (permissionsLookupEnabled) {
				for (int i = 0; i < roles.size(); i ++) {
					List<String> permissions = this.userDao.queryPermissionsByRoleid(roles.get(i));
					if (permissions != null && permissions.size() > 0) {
						info.setStringPermissions(new HashSet<String>(permissions));
					}
				}
			}
		}
		return info;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;
		String userid = upToken.getUsername();
		if (userid == null) {
			throw new AccountException("Null usernames are not allowed by this realm.");
		}
		UserPojo user = null;
		try{
			user = this.userDao.queryUserByUserid(userid);
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (user == null) {
			throw new UnknownAccountException("No account found for user [" + userid + "]");
		}
		SimpleAuthenticationInfo saInfo = new SimpleAuthenticationInfo(userid, user.getPassword(), getName());
		saInfo.setCredentialsSalt(ByteSource.Util.bytes(user.getSalt()));//salt  加密盐值
		return saInfo;
	}

	public static void main(String[] args) {
		String plainTextPassword = "jiaguangzhaojiaguangzhao";
		RandomNumberGenerator rng = new SecureRandomNumberGenerator();
		Object salt = rng.nextBytes();
		String hashedPasswordBase64 = new Sha256Hash(plainTextPassword, salt, 1024).toBase64();
		UserPojo user = new UserPojo();
		user.setUserid("jiaguangzhao");
		user.setUsername("贾广召");
		user.setPassword(plainTextPassword);
		user.setSalt(hashedPasswordBase64);
		user.setEmail("295669145@qq.com");
		log.info("{}, {}", salt, hashedPasswordBase64);
		log.info("{}", salt.toString().length());
		log.info("{}", hashedPasswordBase64.length());
	}
}
